/*
 *  MiloInnovation.cpp
 *  Milovo04alfa00
 *
 *  Created by Luca on 24/11/06.
 *  Copyright 2006 __MyCompanyName__. All rights reserved.
 *
 */

#include "MiloInnovation.h"
//Mil_Int CalcFitnessTest(GeneticRecipes &tmpTabGeneticPopulationRecipes, Mil_Int tmpSelectedGoal, Artifacts *tmpCurrentTabArtifacts, Agents *tmpCurrentTabAgent, Mil_Int tmpCurrentIDAgent, int tmpCurrentDebugLevel);

bool TryInnovation(MilinitParams &tmp_InitParam, SystemParams &tmp_MilovoParam, SimulationParams &tmp_SimulaParam, Mil_Int tmpCurrentIDAgent, 
						 Agents *tmp_TabAgents, Recipes *tmp_TabRecipes, Artifacts *tmp_TabArtifacts, Requests *tmp_TabRequests, 
						 MilovoRandom &tmp_MiloRand, MilovoEnvironment &tmpCurrentMiloEnv)
{
	if(tmpCurrentMiloEnv.GetDebugLevel() >= 1)
		cout << "TryInnovation [begin]" << endl;
	
	Agents::iterator tmp_TabAgentsIter = tmp_TabAgents->find(tmpCurrentIDAgent);
	if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabAgentsIter == tmp_TabAgents->end()))
	{
		cout << "Error in TryInnovation function: cannot find tmp_TabAgentsIter in tmp_TabAgents: " << tmpCurrentIDAgent << endl;
		exit(EXIT_FAILURE);
	}
	bool InnovationSucceded = false;
	vector<Mil_Int> VectIDAgents;
	VectIDAgents.push_back(tmpCurrentIDAgent);
	if((tmp_TabAgentsIter->second.GetFlagGoalDone() == true) || 
		(tmp_MiloRand.GetDoubleRandom(0.0, 1.0) <= tmp_TabAgentsIter->second.Style.GetProbDevelopNewGoal()))
		tmp_TabAgentsIter->second.SetGoal(SelectGoalThisAgent(VectIDAgents, tmp_TabAgents, tmp_TabRecipes, tmp_TabArtifacts, 
																				tmp_TabRequests, tmp_MiloRand, tmpCurrentMiloEnv));

	tmp_TabAgentsIter->second.SetFlagGoalDone(false);
	if(tmpCurrentMiloEnv.GetDebugLevel() >= 2)
		cout << "Innovation Strategy: " << tmp_TabAgentsIter->second.Style.GetInnovationStrategy() << endl;
	switch (tmp_TabAgentsIter->second.Style.GetInnovationStrategy()) 
	{
		case 1:
			InnovationSucceded = InnovationWithoutGoal(tmp_InitParam, tmp_MilovoParam, tmpCurrentIDAgent, tmp_TabAgents, tmp_TabRecipes, 
							  tmp_TabArtifacts, tmp_MiloRand, tmpCurrentMiloEnv.GetCurrentStep(), tmpCurrentMiloEnv.GetDebugLevel());
		break;
		case 2:
			{
				// A Strategy
				InnovationSucceded = InnovationWithGoal(tmp_TabAgentsIter->second.GetGoal(), tmp_InitParam, tmp_MilovoParam, VectIDAgents, tmp_TabAgents, tmp_TabRecipes, 
																				 tmp_TabArtifacts, tmp_MiloRand, tmpCurrentMiloEnv);
				if(InnovationSucceded == true)
				{
					tmp_TabAgentsIter->second.SetNumInnovationSucceded(tmp_TabAgentsIter->second.GetNumInnovationSucceded() + 1);
					Mil_Int IDRequestToCheck = tmp_TabAgentsIter->second.GetIDTempRequest();
					if(IDRequestToCheck != 0)
					{
						Requests::iterator tmp_TabRequestsIter = tmp_TabRequests->find(IDRequestToCheck);
						if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabRequestsIter == tmp_TabRequests->end()))
						{
							cout << "error in TryInnovation function: cannot found tmp_TabRequestsIter in tmp_TabRequests [A strategy]: " << IDRequestToCheck << endl;
							exit(EXIT_FAILURE);
						}
						tmp_TabRequestsIter->second.SetChecked(true);
						tmp_TabRequestsIter->second.SetIDAgentChecked(tmp_TabAgentsIter->second.GetID());
						tmp_TabRequestsIter->second.SetStepChecked(tmpCurrentMiloEnv.GetCurrentStep());
					}
				}
				else tmp_TabAgentsIter->second.SetNumInnovationFailed(tmp_TabAgentsIter->second.GetNumInnovationFailed() + 1);
			}
			break;
		case 3:
			{
				// B strategy
				InnovationSucceded = InnovationWithGoal(tmp_TabAgentsIter->second.GetGoal(), tmp_InitParam, tmp_MilovoParam, VectIDAgents, tmp_TabAgents, tmp_TabRecipes, 
																	tmp_TabArtifacts, tmp_MiloRand, tmpCurrentMiloEnv);
				if(InnovationSucceded == false)
				{
					tmp_TabAgentsIter->second.SetNumInnovationFailed(tmp_TabAgentsIter->second.GetNumInnovationFailed() + 1);

					Mil_Int IDAgentPartner = SelectPartnerInnovatorForThisAgent(tmpCurrentIDAgent, tmp_TabAgents, tmp_MiloRand, tmpCurrentMiloEnv.GetDebugLevel());
					if(IDAgentPartner > 0)
					{
						if(tmpCurrentMiloEnv.GetDebugLevel() >= 3)
							cout << "Agent: " << tmpCurrentIDAgent << " has selected IDAgentPartner: " << IDAgentPartner << endl;
						VectIDAgents.push_back(IDAgentPartner);
						InnovationSucceded = InnovationWithGoal(tmp_TabAgentsIter->second.GetGoal(), tmp_InitParam, tmp_MilovoParam, VectIDAgents, tmp_TabAgents, tmp_TabRecipes, 
																			tmp_TabArtifacts, tmp_MiloRand, tmpCurrentMiloEnv);
						
						SetProjectTheseAgents(VectIDAgents, tmp_TabAgents, InnovationSucceded, tmpCurrentMiloEnv.GetDebugLevel());
						Agents::iterator tmp_TabAgentsPartnerIter = tmp_TabAgents->find(IDAgentPartner);
						if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabAgentsPartnerIter == tmp_TabAgents->end()))
						{
							cout << "Error in TryInnovation function: cannont find tmp_TabAgentsPartnerIter: " << IDAgentPartner << endl;
							exit(EXIT_FAILURE);
						}
						if(InnovationSucceded == true)
						{
							tmp_TabAgentsIter->second.SetNumInnovationSuccededWithPartner(tmp_TabAgentsIter->second.GetNumInnovationSuccededWithPartner() + 1);
							tmp_TabAgentsIter->second.SetNumProjectsSucceded(tmp_TabAgentsIter->second.GetNumProjectsSucceded() + 1);
							tmp_TabAgentsPartnerIter->second.SetNumInnovationSuccededWithPartner(tmp_TabAgentsPartnerIter->second.GetNumInnovationSuccededWithPartner() + 1);
							tmp_TabAgentsPartnerIter->second.SetNumProjectsSucceded(tmp_TabAgentsPartnerIter->second.GetNumProjectsSucceded() + 1);

							Mil_Int IDRequestToCheck = tmp_TabAgentsIter->second.GetIDTempRequest();
							if(IDRequestToCheck != 0)
							{
								Requests::iterator tmp_TabRequestsIter = tmp_TabRequests->find(IDRequestToCheck);
								if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabRequestsIter == tmp_TabRequests->end()))
								{
									cout << "error in TryInnovation function: cannot found tmp_TabRequestsIter in tmp_TabRequests [B strategy]: " << IDRequestToCheck << endl;
									exit(EXIT_FAILURE);
								}
								tmp_TabRequestsIter->second.SetChecked(true);
								tmp_TabRequestsIter->second.SetIDAgentChecked(tmp_TabAgentsIter->second.GetID());
								tmp_TabRequestsIter->second.SetStepChecked(tmpCurrentMiloEnv.GetCurrentStep());
							}
						}
						else 
						{
							tmp_TabAgentsIter->second.SetNumInnovationFailedWithPartner(tmp_TabAgentsIter->second.GetNumInnovationFailedWithPartner() + 1);
							tmp_TabAgentsIter->second.SetNumProjectsFailed(tmp_TabAgentsIter->second.GetNumProjectsFailed() + 1);
							tmp_TabAgentsPartnerIter->second.SetNumInnovationFailedWithPartner(tmp_TabAgentsPartnerIter->second.GetNumInnovationFailedWithPartner() + 1);
							tmp_TabAgentsPartnerIter->second.SetNumProjectsFailed(tmp_TabAgentsPartnerIter->second.GetNumProjectsFailed() + 1);
						}
					}
				}
				else tmp_TabAgentsIter->second.SetNumInnovationSucceded(tmp_TabAgentsIter->second.GetNumInnovationSucceded() + 1);
			}
			break;
		case 4:
			{
				// C strategy
				Mil_Int IDAgentPartner = SelectPartnerInnovatorForThisAgent(tmpCurrentIDAgent, tmp_TabAgents, tmp_MiloRand, tmpCurrentMiloEnv.GetDebugLevel());
				if(IDAgentPartner > 0)
				{
					if(tmpCurrentMiloEnv.GetDebugLevel() >= 3)
						cout << "Agent: " << tmpCurrentIDAgent << " has selected IDAgentPartner: " << IDAgentPartner << endl;
					VectIDAgents.push_back(IDAgentPartner);

					InnovationSucceded = InnovationWithGoal(tmp_TabAgentsIter->second.GetGoal(), tmp_InitParam, tmp_MilovoParam, VectIDAgents, tmp_TabAgents, tmp_TabRecipes, 
																		tmp_TabArtifacts, tmp_MiloRand, tmpCurrentMiloEnv);
					
					SetProjectTheseAgents(VectIDAgents, tmp_TabAgents, InnovationSucceded, tmpCurrentMiloEnv.GetDebugLevel());
					Agents::iterator tmp_TabAgentsPartnerIter = tmp_TabAgents->find(IDAgentPartner);
					if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabAgentsPartnerIter == tmp_TabAgents->end()))
					{
						cout << "Error in TryInnovation function: cannont find tmp_TabAgentsPartnerIter: " << IDAgentPartner << endl;
						exit(EXIT_FAILURE);
					}
					if(InnovationSucceded == true)
					{
						tmp_TabAgentsIter->second.SetNumInnovationSuccededWithPartner(tmp_TabAgentsIter->second.GetNumInnovationSuccededWithPartner() + 1);
						tmp_TabAgentsIter->second.SetNumProjectsSucceded(tmp_TabAgentsIter->second.GetNumProjectsSucceded() + 1);
						tmp_TabAgentsPartnerIter->second.SetNumInnovationSuccededWithPartner(tmp_TabAgentsPartnerIter->second.GetNumInnovationSuccededWithPartner() + 1);
						tmp_TabAgentsPartnerIter->second.SetNumProjectsSucceded(tmp_TabAgentsPartnerIter->second.GetNumProjectsSucceded() + 1);

						Mil_Int IDRequestToCheck = tmp_TabAgentsIter->second.GetIDTempRequest();
						if(IDRequestToCheck != 0)
						{
							Requests::iterator tmp_TabRequestsIter = tmp_TabRequests->find(IDRequestToCheck);
							if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabRequestsIter == tmp_TabRequests->end()))
							{
								cout << "error in TryInnovation function: cannot found tmp_TabRequestsIter in tmp_TabRequests [C strategy]: " << IDRequestToCheck << endl;
								exit(EXIT_FAILURE);
							}
							tmp_TabRequestsIter->second.SetChecked(true);
							tmp_TabRequestsIter->second.SetIDAgentChecked(tmp_TabAgentsIter->second.GetID());
							tmp_TabRequestsIter->second.SetStepChecked(tmpCurrentMiloEnv.GetCurrentStep());
						}
					}
					else 
					{
						tmp_TabAgentsIter->second.SetNumInnovationFailedWithPartner(tmp_TabAgentsIter->second.GetNumInnovationFailedWithPartner() + 1);
						tmp_TabAgentsIter->second.SetNumProjectsFailed(tmp_TabAgentsIter->second.GetNumProjectsFailed() + 1);
						tmp_TabAgentsPartnerIter->second.SetNumInnovationFailedWithPartner(tmp_TabAgentsPartnerIter->second.GetNumInnovationFailedWithPartner() + 1);
						tmp_TabAgentsPartnerIter->second.SetNumProjectsFailed(tmp_TabAgentsPartnerIter->second.GetNumProjectsFailed() + 1);
					}
				}
			}
			break;
		default:
			break;
	}

	if(InnovationSucceded == true)
		tmp_TabAgentsIter->second.SetFlagGoalDone(true);
	
	if(tmpCurrentMiloEnv.GetDebugLevel() >= 1)
		cout << "TryInnovation [end]" << endl;

	return(InnovationSucceded);
}	

bool InnovationWithoutGoal(MilinitParams &tmp_InitParam, SystemParams &tmp_MilovoParam, Mil_Int tmpCurrentIDAgent, Agents *tmp_TabAgents, 
									Recipes *tmp_TabRecipes, Artifacts *tmp_TabArtifacts, MilovoRandom &tmp_MiloRand, Mil_Int tmpCurrentStep, 
									int tmp_DebugLevel)
{
	vector<Mil_Int> VectIDArtifactsAvailable;
	ExtractVectIDArtifactsKnowedByThisAgent(VectIDArtifactsAvailable, tmpCurrentIDAgent, tmp_TabAgents, tmp_TabRecipes, tmp_TabArtifacts, tmp_DebugLevel);
	if((tmp_DebugLevel >= 0) && (VectIDArtifactsAvailable.size() == 0))
		return false;

	list<Mil_Int> tmpListIDInput;
	list<Mil_Int> tmpListOperators;
	// select number of artifacts constituents recipe to create
	Mil_Int tmpHowManyArtifactsThisRecipe = tmp_MiloRand.GetIntRandom(tmp_InitParam.GetNumMinArtifactsPerRecipe(), tmp_InitParam.GetNumMaxArtifactsPerRecipe());
	// insert artifacts in a list manage by recipe
	for(Mil_Int tmpHowManyArtifactsThisRecipeIndex = 0; tmpHowManyArtifactsThisRecipeIndex < tmpHowManyArtifactsThisRecipe; tmpHowManyArtifactsThisRecipeIndex++)
	tmpListIDInput.push_back(VectIDArtifactsAvailable[tmp_MiloRand.GetIntRandom(0, (VectIDArtifactsAvailable.size() - 1))]);
	// insert operators in a list manage by recipe
	Mil_Int tmpHowManyOperatorsThisRecipe = tmpHowManyArtifactsThisRecipe - 1;
	for(Mil_Int tmpHowManyOperatorsThisRecipeIndex = 0; tmpHowManyOperatorsThisRecipeIndex < tmpHowManyOperatorsThisRecipe; tmpHowManyOperatorsThisRecipeIndex++)
	tmpListOperators.push_back(tmp_InitParam.VectOperators[tmp_MiloRand.GetIntRandom(0, tmp_InitParam.VectOperators.size() - 1)]);
	// calculate output of this new recipe
	Mil_Int tmpOutputThisRecipe = CalcOutputThisRecipe(tmpListIDInput, tmpListOperators, tmp_TabArtifacts, tmp_DebugLevel);
	// prepare a vector within the artifacts name that output recipe cannot assume
	vector<Mil_Int> VectToCompareForOutput;
	vector<Mil_Int> VectIDAgentsToAnalize;
	VectIDAgentsToAnalize.push_back(tmpCurrentIDAgent);
	CheckOutputThisAgentToCompare(VectToCompareForOutput, tmp_InitParam, VectIDAgentsToAnalize, tmp_TabAgents, tmp_TabRecipes, tmp_TabArtifacts, tmp_DebugLevel);
	// check if output is into boundaries and its name is different to raw materials
	bool InnovationSucceded = false;
	tmpOutputThisRecipe = ValidateThisOutputRecipe(tmp_MilovoParam.GetMinNameArtifactAllowed(), tmp_MilovoParam.GetMaxNameArtifactAllowed(), 
																  VectToCompareForOutput, tmpOutputThisRecipe, 0, tmp_TabAgents, tmpCurrentIDAgent, 
																  tmp_InitParam, tmp_DebugLevel);
	if(tmpOutputThisRecipe != 0)
	{
		InsertNewRecipe(tmp_InitParam, tmp_MilovoParam, tmp_MiloRand, tmp_TabAgents, tmpCurrentIDAgent, tmp_TabRecipes, tmp_TabArtifacts, tmpListIDInput, 
							 tmpListOperators, tmpOutputThisRecipe, tmpHowManyArtifactsThisRecipe, tmpCurrentStep, tmp_DebugLevel);
		InnovationSucceded = true;
	}
	
	return(InnovationSucceded);
}

bool InnovationWithGoal(Mil_Int tmpSelectedGoal, MilinitParams &tmp_Init_Param, SystemParams &tmp_Milovo_Param, 
								vector<Mil_Int> &VectIDAgentsToAnalize, Agents *CurrentTabAgents, Recipes *CurrentTabRecipes, Artifacts *CurrentTabArtifacts, 
								MilovoRandom &tmp_Milo_Rand, MilovoEnvironment &tmp_CurrentMiloEnv)
{
	if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
		cout << "--- Init innovation for Agent: " << VectIDAgentsToAnalize[0] << " --- [Begin] ---" << endl;
	bool InnovationSucceded = false;
	// If this agent cannot select a goal function return false.
	if(tmpSelectedGoal == 0)
		return(false);
	// this TabGeneticPopulationRecipes is a specific table for guest the virtual
	// population of recipes for genetic algorithm
	GeneticRecipes TabGeneticPopulationRecipes;
	if(tmp_Milovo_Param.GetInitPopulationType() == 1)
	{
		if(InitGeneticPopulationRecipes(tmp_Init_Param, tmp_Milovo_Param, TabGeneticPopulationRecipes, VectIDAgentsToAnalize, CurrentTabAgents, 
												  CurrentTabRecipes, CurrentTabArtifacts, tmp_Milo_Rand, tmp_CurrentMiloEnv.GetDebugLevel()) == false)
		return(false);
	}
	else
	{
		if(InitRandomGeneticPopulationRecipes(tmp_Init_Param, tmp_Milovo_Param, TabGeneticPopulationRecipes, VectIDAgentsToAnalize, CurrentTabAgents, 
														  CurrentTabRecipes, CurrentTabArtifacts, tmp_Milo_Rand, tmp_CurrentMiloEnv.GetDebugLevel()) == false)
			return(false);
	}

	Mil_Int HowManyGenerations = 1;
	Mil_Int tmpIDGeneticRecipeFound = CalcFitness(TabGeneticPopulationRecipes, tmpSelectedGoal, CurrentTabArtifacts, tmp_CurrentMiloEnv.GetDebugLevel());
	while((tmpIDGeneticRecipeFound == 0) && (HowManyGenerations <= tmp_Milovo_Param.GetNumGeneticGenerations()))
	{
		if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
			cout << "\t-- Generation n. " << HowManyGenerations << " -- [begin] -- " << endl;
		GeneticRecipes TabTempGeneticPopulationRecipes;
		for(Mil_Int tmpNumCoupling = 1; tmpNumCoupling <= (TabGeneticPopulationRecipes.size() / 2); tmpNumCoupling++)
		{
			if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
				cout << "tmpNumCoupling:" << tmpNumCoupling << " -- [begin] --" << endl;
			
			vector<Mil_Int> VectParents;
			SelectParents(TabGeneticPopulationRecipes, VectParents, tmp_Milo_Rand, tmp_CurrentMiloEnv.GetDebugLevel());
			CrossOver(TabGeneticPopulationRecipes, TabTempGeneticPopulationRecipes, VectParents, tmp_Milo_Rand, tmp_CurrentMiloEnv.GetDebugLevel());

			if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
				cout << "tmpNumCoupling:" << tmpNumCoupling << " -- [end] --" << endl;
		}
		UpdateGeneticPopulationRecipes(TabGeneticPopulationRecipes, TabTempGeneticPopulationRecipes, tmp_CurrentMiloEnv.GetDebugLevel());
		// calculate fitness of genetic recipes population. If mean of fitness is equal to median of fitness, 
		// algorithm stop and return the ID of genetic recipe with max fitness; else return 0.
		tmpIDGeneticRecipeFound = CalcFitness(TabGeneticPopulationRecipes, tmpSelectedGoal, CurrentTabArtifacts, tmp_CurrentMiloEnv.GetDebugLevel());
		
		if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
			cout << "\t-- Generation n. " << HowManyGenerations << " -- [end] -- tmpIDGeneticRecipeFound: " << tmpIDGeneticRecipeFound  << endl;
		
		HowManyGenerations++;
	}
	
	if(tmpIDGeneticRecipeFound != 0)
	{
		GeneticRecipes::iterator TabGeneticPopulationRecipesIter = TabGeneticPopulationRecipes.find(tmpIDGeneticRecipeFound);
		if((tmp_CurrentMiloEnv.GetDebugLevel() >= 0) && (TabGeneticPopulationRecipesIter == TabGeneticPopulationRecipes.end()))
		{
			cout << "Error in InnovationWitGoal: cannot find TabGeneticPopulationRecipesIter in TabGeneticPopulationRecipes for new Recipe!" << endl;
			exit(EXIT_FAILURE);
		}
		vector<Mil_Int> VectToCompareForOutput;
		CheckOutputThisAgentToCompare(VectToCompareForOutput, tmp_Init_Param, VectIDAgentsToAnalize, CurrentTabAgents, CurrentTabRecipes, 
												CurrentTabArtifacts, tmp_CurrentMiloEnv.GetDebugLevel());
		// check if output is into boundaries and its name is different to raw materials
		if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
			cout << "ArtOutput in TabGeneticRecipe for compare with goal: " << TabGeneticPopulationRecipesIter->second.GetOutputName() << " Before" << endl;

		TabGeneticPopulationRecipesIter->second.SetOutputName(ValidateThisOutputRecipe(tmp_Milovo_Param.GetMinNameArtifactAllowed(), tmp_Milovo_Param.GetMaxNameArtifactAllowed(), 
											 VectToCompareForOutput, TabGeneticPopulationRecipesIter->second.GetOutputName(), tmpSelectedGoal, CurrentTabAgents, 
											 VectIDAgentsToAnalize[0], tmp_Init_Param, tmp_CurrentMiloEnv.GetDebugLevel()));

		if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
			cout << "ArtOutput in TabGeneticRecipe for compare with goal: " << TabGeneticPopulationRecipesIter->second.GetOutputName() << " After" << endl;
		
		if(TabGeneticPopulationRecipesIter->second.GetOutputName() != 0)
		{
			list<Mil_Int> tmpListInputs;
			list<Mil_Int> tmpListOperators;
			for(list<Mil_Int>::iterator LinksIDArtifactsIter = TabGeneticPopulationRecipesIter->second.LinksIDArtifacts.begin(); LinksIDArtifactsIter != TabGeneticPopulationRecipesIter->second.LinksIDArtifacts.end(); LinksIDArtifactsIter++)
				tmpListInputs.push_back(*LinksIDArtifactsIter);
			for(list<Mil_Int>::iterator LinksOperatorsIter = TabGeneticPopulationRecipesIter->second.LinksOperators.begin(); LinksOperatorsIter != TabGeneticPopulationRecipesIter->second.LinksOperators.end(); LinksOperatorsIter++)
				tmpListOperators.push_back(*LinksOperatorsIter);
			
			for(vector<Mil_Int>::iterator VectIDAgentsToAnalizeIter = VectIDAgentsToAnalize.begin(); VectIDAgentsToAnalizeIter != VectIDAgentsToAnalize.end(); VectIDAgentsToAnalizeIter++)
			{
				Mil_Int tmpIDAgentToAnalize = *VectIDAgentsToAnalizeIter;
				InsertNewRecipe(tmp_Init_Param, tmp_Milovo_Param, tmp_Milo_Rand, CurrentTabAgents, tmpIDAgentToAnalize, CurrentTabRecipes, 
									 CurrentTabArtifacts, tmpListInputs, tmpListOperators, TabGeneticPopulationRecipesIter->second.GetOutputName(), 
									 TabGeneticPopulationRecipesIter->second.LinksIDArtifacts.size(), tmp_CurrentMiloEnv.GetCurrentStep(), 
									 tmp_CurrentMiloEnv.GetDebugLevel());
				if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
					cout << "Insert new GenRecipe: " << tmpIDGeneticRecipeFound << " for agent: " << tmpIDAgentToAnalize << endl;
			}
			InnovationSucceded = true;
		}
	}	
	if(tmp_CurrentMiloEnv.GetDebugLevel() >= 2)
		cout << "--- Init innovation for Agent: " << VectIDAgentsToAnalize[0] << " --- [End] --- --> Goal Selected: " << tmpSelectedGoal << endl;
	
	return(InnovationSucceded);
}

Mil_Int SelectPartnerInnovatorForThisAgent(Mil_Int tmp_CurrentIDAgent, Agents *tmp_CurrentTabAgents, MilovoRandom &tmp_CurrentMiloRand, 
														 int tmp_CurrentDebugLevel)
{
	Agents::iterator tmp_CurrentTabAgentsIter = tmp_CurrentTabAgents->find(tmp_CurrentIDAgent);
	if((tmp_CurrentDebugLevel >= 0) && (tmp_CurrentTabAgentsIter == tmp_CurrentTabAgents->end()))
	{
		cout << "Error in SelectPartnerInnovatorForThisAgent: cannot find tmp_CurrentTabAgentsIter in tmp_CurrentTabAgents: " << tmp_CurrentIDAgent << endl;
		exit(EXIT_FAILURE);
	}
	Mil_Int PartnerSelected = 0;
	switch(tmp_CurrentTabAgentsIter->second.Style.GetSelectPartnerMode())
	{
		case 1:
			{
				// calculate the sum of votes given by this agent to others
				Mil_Double SumVotesThisAgent = 0.0;
				for(Relationships::iterator TabRelationshipsIter = tmp_CurrentTabAgentsIter->second.TabRelationships.begin(); TabRelationshipsIter != tmp_CurrentTabAgentsIter->second.TabRelationships.end(); TabRelationshipsIter++)
				{
					Agents::iterator tmp_CurrentTabAgents_PartnerIter = tmp_CurrentTabAgents->find(TabRelationshipsIter->second.GetIDAgentPartner());
					if((tmp_CurrentTabAgents_PartnerIter != tmp_CurrentTabAgents->end()) && (tmp_CurrentTabAgents_PartnerIter->second.GetID() != 0))
						SumVotesThisAgent += TabRelationshipsIter->second.GetVote();
				}
				
				Mil_Double PartenerSelector = tmp_CurrentMiloRand.GetDoubleRandom(0.0, 1.0);
				Mil_Double tmpPartialSumVoteToAnalize = 0.0;
				bool FlagPartnerFound = false;
				Relationships::iterator TabRelationshipsIter = tmp_CurrentTabAgentsIter->second.TabRelationships.begin();
				while((FlagPartnerFound == false) && (TabRelationshipsIter != tmp_CurrentTabAgentsIter->second.TabRelationships.end()))
				{
					Agents::iterator tmp_CurrentTabAgents_PartnerIter = tmp_CurrentTabAgents->find(TabRelationshipsIter->second.GetIDAgentPartner());
					if((tmp_CurrentTabAgents_PartnerIter != tmp_CurrentTabAgents->end()) && (tmp_CurrentTabAgents_PartnerIter->second.GetID() != 0))
						tmpPartialSumVoteToAnalize += TabRelationshipsIter->second.GetVote() / SumVotesThisAgent;
						
					if(tmpPartialSumVoteToAnalize >= PartenerSelector)
					{
						if((tmp_CurrentTabAgents_PartnerIter != tmp_CurrentTabAgents->end()) && 
							(tmp_CurrentTabAgents_PartnerIter->second.GetID() != tmp_CurrentIDAgent) &&
							(tmp_CurrentTabAgents_PartnerIter->second.GetID() != 0))
						{
							PartnerSelected = TabRelationshipsIter->second.GetIDAgentPartner();
							FlagPartnerFound = true;
						}
					}
					TabRelationshipsIter++;
				}
			}
			break;
		case 2:
			{
				// random select
				vector<Mil_Int> tmpVectIDFriendsThisAgent;
				for(Relationships::iterator TabRelationshipsIter = tmp_CurrentTabAgentsIter->second.TabRelationships.begin(); TabRelationshipsIter != tmp_CurrentTabAgentsIter->second.TabRelationships.end(); TabRelationshipsIter++)
				{
					Agents::iterator tmp_CurrentTabAgents_PartnerIter = tmp_CurrentTabAgents->find(TabRelationshipsIter->second.GetIDAgentPartner());
					if((tmp_CurrentTabAgents_PartnerIter != tmp_CurrentTabAgents->end()) && 
						(tmp_CurrentTabAgents_PartnerIter->second.GetID() != tmp_CurrentIDAgent) &&
						(tmp_CurrentTabAgents_PartnerIter->second.GetID() != 0))
						tmpVectIDFriendsThisAgent.push_back(TabRelationshipsIter->second.GetIDAgentPartner());
				}
				if((tmp_CurrentDebugLevel >= 0) &&(tmpVectIDFriendsThisAgent.empty() == true))
				{
					cout << "Error in SelectPartnerInnovatorForThisAgent: tmpVectIDFriendsThisAgent is empty!!" << endl;
					exit(EXIT_FAILURE);
				}
				PartnerSelected = tmpVectIDFriendsThisAgent[tmp_CurrentMiloRand.GetIntRandom(0, (tmpVectIDFriendsThisAgent.size() - 1))];
			}
			break;
	}
	return(PartnerSelected);
}

